#!/usr/bin/python

import pprint
import math

from sys import argv

# Some globals
diceSides = 8
debug = False

pp = pprint.PrettyPrinter(indent=4)

def getProbDicts(params):

    # Obtain a dict of all possible outcomes
    atkOutcomes = getRawOutcomes(params['atkDice'])
    defOutcomes = getRawOutcomes(params['defDice'])

    # Determine the probabilities of specific MoS values
    successDict = getSuccessDistribution(params, atkOutcomes, defOutcomes)
    if params['mosBase'] is not 0:
        base = params['mosBase']
        mosSum = 0.0
        for key in successDict.iterkeys():
            if key >= base:
                mosSum = mosSum + successDict[key]
        print "Sum of MoS %i+ is: %2.2f" % (base, mosSum)
    pp.pprint(successDict)

def getSuccessDistribution(params, atkResults, defResults):
   
    atkMod = params['atkMod'] 
    defMod = params['defMod']
    rngDict = getResult(atkResults, atkMod, defResults, defMod)
    return rngDict

def getResult(atkResults, atkMod, defResults, defMod):
    results = {}
    count = 0
    for atkDiceRes in atkResults:
        atkRes = atkDiceRes + atkMod
        if atkRes < 0: 
            atkRes = 0

        for defDiceRes in defResults:
            defRes = defDiceRes + defMod
            if defRes < 0:
                defRes = 0
            
            result = 0
            if atkRes > defRes:
                result = atkRes - defRes

            count = count + 1
            if result in results:
                results[result] = results[result] + 1
            else:
                results[result] = 1

            if debug:
                print "%iD%i%+i = %i + %i = %i vs. %iD%i%+i = %i + %i = %i -> %i" % (
                    params['atkDice'], diceSides, atkMod, atkDiceRes, atkMod, atkRes,
                    params['defDice'], diceSides, defMod, defDiceRes, defMod, defRes,
                    result)
    
    checkCount = 0    
    for x in results.iterkeys():
        y = results[x]
        prob = (float(results[x]) / float(count)) * 100.0
        if debug:
            print "  MoS %i has %i occurances (%2.3f)" % (x, y, prob)
        results[x] = prob

        checkCount = checkCount + y
    if debug:
        totalCount = len(atkResults) * len(defResults)
        print "Predicted %i | Observed: %i" % (totalCount, checkCount)

    return results

def getRawOutcomes(numDice):
    outcomes = []

    maxOutcome = numDice + 1    
    if numDice == 0:
        maxOutcome = 3

    # Generate the raw list that contains all possible outcomes
    for x in range(1, maxOutcome):
        outcomes = appendDiceSides(outcomes, diceSides)
    
    # For each element, reduce it to a pre-modifier value
    results = []
    for x in outcomes:
        res = 1
        if numDice is 0:
            res = min(x);
        else:
            for y in x:
                if y > res:
                    res = y
                elif y is 6 and res >= 6:
                    res = res +1

        if res is 1:
            res = 0

        results.append(res);
            
        if debug:
            print "Outcome of %sD is %s with a value of %i " % (numDice, x, res)

    return results

def appendDiceSides(diceList, diceSides):

    if len(diceList) is 0:
        for x in range(1, diceSides+1):
            diceList.append([x])
        return diceList

    newList = []
    for y in diceList:
        # y is an element of list type
        for x in range(1, diceSides+1):
            z = y[:]
            z.append(x)
            newList.append(z)

    return newList

if __name__ == '__main__':
    params = {
        'atkDice': 2,
        'atkMod': 0,
        'defDice': 2,
        'defMod': 0,
        'mosBase' : 1,
    }

    if len(argv) >= 2:
        params['atkDice'] = int(argv[1])
    if len(argv) >= 3:
        params['atkMod'] = int(argv[2])
    if len(argv) >= 4:
        params['defDice'] = int(argv[3])
    if len(argv) >= 5:
        params['defMod'] = int(argv[4])
    if len(argv) >= 6:
        params['mosBase'] = int(argv[5])

    probDict = getProbDicts(params)

